package com.financing.wap.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.financing.wap.dto.FaUserWechatDTO;
import com.financing.wap.weixin.dto.AccessTicket;
import com.financing.wap.weixin.dto.AccessToken;
import com.financing.wap.weixin.dto.SendRedPack;
import com.financing.wap.weixin.resp.SendRedPackResp;

/**
 * 微信接口-工具类
 * @author lisu
 *
 */
public class WechatUtil {

	private static Logger logger = Logger.getLogger(WechatUtil.class);

	//开放-微信登陆 (1)生成二维码
	public static String open_weixin_login = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
	//开放-微信登陆 (2)获取 access_token
	public static String open_access_token = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
	//开放-微信登陆 (3)通过access_token调用用户信息接口
	public static String open_user_info = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
	
	// 获取access_token的接口地址（GET） 限200（次/天）
	public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
	
	// 获取jsapi_ticket的接口地址（GET） 限200（次/天）
	public final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
	
	// 用于企业向微信用户个人发现金红包
	public final static String send_red_pack = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
	
	// 根据media_id 下载微信图片
	public final static String media_get = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
	/**
	 * 发起https请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求地址
	 * @param requestMethod
	 *            请求方式（GET、POST）
	 * @param outputStr
	 *            提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 */
	public static JSONObject httpsRequest(String requestUrl,
			String requestMethod, String outputStr) {
		JSONObject jsonObject = null;
		StringBuffer buffer = new StringBuffer();
		try {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
					.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod))
				httpUrlConn.connect();

			// 当有数据需要提交时
			if (null != outputStr) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(
					inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			jsonObject = JSONObject.fromObject(buffer.toString());
		} catch (ConnectException ce) {
			logger.error("Weixin server connection timed out.", ce);
		} catch (Exception e) {
			logger.error("https request error:{}", e);
		}
		return jsonObject;
	}

	/**
	 * 发起http请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求地址
	 * @param requestMethod
	 *            请求方式（GET、POST）
	 * @param outputStr
	 *            提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 * @throws Exception
	 */
	public static JSONObject httpRequest(String requestUrl,
			String requestMethod, String outputStr, String type)
			throws Exception {
		JSONObject jsonObject = null;
		// 定义数据分隔符
		String boundary = "------------7da2e536604c8";
		try {
			URL uploadUrl = new URL(requestUrl);
			HttpURLConnection uploadConn = (HttpURLConnection) uploadUrl
					.openConnection();
			uploadConn.setDoOutput(true);
			uploadConn.setDoInput(true);
			uploadConn.setRequestMethod("POST");
			// 设置请求头Content-Type
			uploadConn.setRequestProperty("Content-Type",
					"multipart/form-data;boundary=" + boundary);
			// 获取媒体文件上传的输出流（往微信服务器写数据）
			OutputStream outputStream = uploadConn.getOutputStream();

			URL mediaUrl = new URL(outputStr);
			HttpURLConnection meidaConn = (HttpURLConnection) mediaUrl
					.openConnection();
			meidaConn.setDoOutput(true);
			meidaConn.setRequestMethod("GET");

			// 从请求头中获取内容类型
			String contentType = meidaConn.getHeaderField("Content-Type");
			// 根据内容类型判断文件扩展名
			String fileExt = ".jpg";
			// 请求体开始
			outputStream.write(("--" + boundary + "\r\n").getBytes());
			outputStream
					.write(String
							.format("Content-Disposition: form-data; name=\"media\"; filename=\"file1%s\"\r\n",
									fileExt).getBytes());
			outputStream.write(String.format("Content-Type: %s\r\n\r\n",
					contentType).getBytes());

			// 获取媒体文件的输入流（读取文件）
			BufferedInputStream bis = new BufferedInputStream(
					meidaConn.getInputStream());
			byte[] buf = new byte[8096];
			int size = 0;
			while ((size = bis.read(buf)) != -1) {
				// 将媒体文件写到输出流（往微信服务器写数据）
				outputStream.write(buf, 0, size);
			}
			// 请求体结束
			outputStream.write(("\r\n--" + boundary + "--\r\n").getBytes());
			outputStream.close();
			bis.close();
			meidaConn.disconnect();

			// 获取媒体文件上传的输入流（从微信服务器读数据）
			InputStream inputStream = uploadConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(
					inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);
			StringBuffer buffer = new StringBuffer();
			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			uploadConn.disconnect();

			// 使用JSON-lib解析返回结果
			jsonObject = JSONObject.fromObject(buffer.toString());
		} catch (Exception e) {
			logger.error("http request error:{}", e);
		}
		return jsonObject;
	}
	 public static InputStream getInputStream(String mediaId,String accessToken) {


	       InputStream is = null;
	       
	   	String url = media_get.replace("MEDIA_ID", mediaId).replace(
				"ACCESS_TOKEN", accessToken);

	       try {

//	           URL urlGet = new URL(url);
//
//	           HttpURLConnection http = (HttpURLConnection) urlGet
//
//	                   .openConnection();
//
//	           http.setRequestMethod("GET"); // 必须是get方式请求
//
//	           http.setRequestProperty("Content-Type",
//
//	                   "application/x-www-form-urlencoded");
//
//	           http.setDoOutput(true);
//
//	           http.setDoInput(true);
//
//	           System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
//
//	           System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
//
//	           http.connect();
//
//	           // 获取文件转化为byte流	        
//	           is = http.getInputStream();
	    	   
	    	// is= HttpClientUtil.getInstance().doGetRequestStream(url,path);
	    	  

	       } catch (Exception e) {

	    	   logger.error("http request error:", e);

	       }

	       return is;

	   }

	   /**

	    * 获取下载图片信息（jpg）

	    * 

	    * @param mediaId

	    *            文件的id

	    * @throws Exception

	    */

	   public static boolean saveImageToDisk(String mediaId,String accessToken,String filePath) throws Exception {
		   	String url = media_get.replace("MEDIA_ID", mediaId).replace(
					"ACCESS_TOKEN", accessToken);
		  
	       return 	HttpClientUtil.getInstance().doGetRequestStream(url,filePath);
	 }

	/**
	 * 开放-微信登陆 (1) 生成 二维码
	 * 
	 * @param map
	 *            参数实例
	 * @param accessToken
	 *            有效的access_token
	 * @return 0表示成功，其他值表示失败
	 */
	public static String getOpenWeixinLoginURL(String appid,String redirect_uri,String state) {

		// 生成 二维码
		String url = open_weixin_login.replace("APPID", appid)
									  .replace("REDIRECT_URI", redirect_uri)
									  .replace("SCOPE", "snsapi_login")
								      .replace("STATE", state);
		
		return url;
	}
	/**
	 * 开放-微信登陆 (2)获取 access_token
	 * 
	 * @param map
	 *            参数实例
	 * @param accessToken
	 *            有效的access_token
	 * @return 0表示成功，其他值表示失败
	 */
	public static Map<String,Object>  getOpenAccessToken(String appid,String secret,String code) {

		// 获取 access_token
		String url = open_access_token.replace("APPID", appid)
									  .replace("SECRET", secret)
									  .replace("CODE", code);
		
		JSONObject jsonObject = httpsRequest(url, "POST", null);
		System.out.println("=====微信联合登录=====");
		System.out.println(url);
		System.out.println(jsonObject);
		Map<String,Object> map = null;
		if (null != jsonObject) {
			try {
				map = new HashMap<String,Object>();
				map.put("access_token", jsonObject.getString("access_token"));
				map.put("openid", jsonObject.getString("openid"));
			} catch (JSONException e) {
				map = null;
				// 获取token失败
				logger.error(
						"getAccessToken error errcode:"
								+ jsonObject.getInt("errcode") + ";errmsg:"
								+ jsonObject.getString("errmsg"), e);
			}
		}
		
		return map;
	}
	
	/**
	 * 开放-微信登陆 (3) 通过access_token调用用户信息接口
	 * 
	 * @param map
	 *            参数实例
	 * @param accessToken
	 *            有效的access_token
	 * @return 0表示成功，其他值表示失败
	 */
	public static FaUserWechatDTO  getOpenUserinfo(String access_token,String openid) {

		// 通过access_token调用用户信息接口
		String url = open_user_info.replace("ACCESS_TOKEN", access_token)
									  .replace("OPENID", openid);
		
		// 调用接口删除菜单
		JSONObject jsonObject = httpsRequest(url, "POST", null);

		FaUserWechatDTO bean = null;
		if (null != jsonObject) {
			logger.info("getOpenUserinfo:"+jsonObject.toString());
			try {
				bean = new FaUserWechatDTO();
				bean.setOpenid(jsonObject.getString("openid"));
				bean.setNickname(jsonObject.getString("nickname"));
				bean.setSex(jsonObject.getString("sex"));
				bean.setProvince(jsonObject.getString("province"));
				bean.setCity(jsonObject.getString("city"));
				bean.setCountry(jsonObject.getString("country"));
				bean.setHeadimgurl(jsonObject.getString("headimgurl"));
				bean.setPrivilege(jsonObject.getString("privilege"));
				try{
					bean.setUnionid(jsonObject.getString("unionid"));
				} catch(JSONException c){
				}

			} catch (JSONException e) {
				bean = null;
				// 获取token失败
				logger.error(
						"getAccessToken error errcode:"
								+ jsonObject.getInt("errcode") + ";errmsg:"
								+ jsonObject.getString("errmsg"), e);
			}
		}
		
		return bean;
	}
	/**
	 * 获取access_token
	 * 
	 * @param appid
	 *            凭证
	 * @param appsecret
	 *            密钥
	 * @return
	 */
	public static AccessToken getAccessToken(String appid, String appsecret) {
		AccessToken accessToken = null;

		String requestUrl = access_token_url.replace("APPID", appid).replace(
				"APPSECRET", appsecret);
		JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
		// 如果请求成功
		if (null != jsonObject) {
			try {
				accessToken = new AccessToken();
				accessToken.setToken(jsonObject.getString("access_token"));
				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
			} catch (JSONException e) {
				accessToken = null;
				// 获取token失败
				logger.error(
						"getAccessToken error errcode:"
								+ jsonObject.getInt("errcode") + ";errmsg:"
								+ jsonObject.getString("errmsg"), e);
			}
		}
		return accessToken;
	}
	/**
	 * 获取access_ticket
	 * 
	 * @param AccessToken
	 * @return
	 */
	public static AccessTicket getAccessTicket(String accessToken) {
		AccessTicket accessTicket = null;

		String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", accessToken);
		JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
		// 如果请求成功
		if (null != jsonObject) {
			try {
				accessTicket = new AccessTicket();
				accessTicket.setTicket(jsonObject.getString("ticket"));
				accessTicket.setExpiresIn(jsonObject.getInt("expires_in"));
			} catch (JSONException e) {
				accessToken = null;
				// 获取token失败
				logger.error(
						"getAccessTicket error errcode:"
								+ jsonObject.getInt("errcode") + ";errmsg:"
								+ jsonObject.getString("errmsg"), e);
			}
		}
		return accessTicket;
	}
	/**
	 * 发起https请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求地址
	 * @param requestMethod
	 *            请求方式（GET、POST）
	 * @param outputStr
	 *            提交的数据
	 * @return Document(通过dom4j的方式获取xml对象的属性值)
	 */
	public static Document httpsRequestForCert(String requestUrl,
			String requestMethod, String outputStr,String certPath,String certNum) {
		Document document = null;
		StringBuffer buffer = new StringBuffer();
		try {
			/*// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());*/
			
			KeyStore keyStore  = KeyStore.getInstance("PKCS12");
	        FileInputStream instream = new FileInputStream(new File(certPath));
	        try {
	            keyStore.load(instream, certNum.toCharArray());
	        } finally {
	            instream.close();
	        }

	        // Trust own CA and all self-signed certs
	        SSLContext sslcontext = SSLContexts.custom()
	                .loadKeyMaterial(keyStore, certNum.toCharArray())
	                .build();
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslcontext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
					.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod))
				httpUrlConn.connect();

			// 当有数据需要提交时
			if (null != outputStr) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(
					inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			document = DocumentHelper.parseText(buffer.toString());
		} catch (ConnectException ce) {
			logger.error("Weixin server connection timed out.", ce);
		} catch (Exception e) {
			logger.error("https request error:{}", e);
		}
		return document;
	}
	
		/**
	 * 获取access_ticket
	 * 
	 * @param AccessToken
	 * @return
	 */
	public static SendRedPackResp sendRedPack(SendRedPack object) {
		SendRedPackResp bean = null;
		Document document = httpsRequestForCert(send_red_pack, "POST", com.financing.wap.weixin.util.MessageUtil.textMessageToXml(object).replaceAll("__", "_"),WeChatGiftXMLUtil.map.get(WeChatGiftXMLUtil.CERT_PATH),WeChatGiftXMLUtil.map.get(WeChatGiftXMLUtil.ELEMENT_MCH_ID));
		// 如果请求成功
		if (null != document) {
			Element rootElement=document.getRootElement(); 
			try {
				bean = new SendRedPackResp();
				String return_code = rootElement.elementText("return_code");
				String return_msg = rootElement.elementText("return_msg");
				String sign = rootElement.elementText("sign");
				String result_code = rootElement.elementText("result_code");
				String err_code = rootElement.elementText("err_code");
				String err_code_des = rootElement.elementText("err_code_des");
				String mch_billno = rootElement.elementText("mch_billno");
				String mch_id = rootElement.elementText("mch_id");
				String wxappid = rootElement.elementText("wxappid");
				String re_openid = rootElement.elementText("re_openid");
				String total_amount = rootElement.elementText("total_amount");
				bean.setErr_code(err_code);
				bean.setErr_code_des(err_code_des);
				bean.setMch_billno(mch_billno);
				bean.setMch_id(mch_id);
				bean.setRe_openid(re_openid);
				bean.setResult_code(result_code);
				bean.setReturn_code(return_code);
				bean.setReturn_msg(return_msg);
				bean.setSign(sign);
				bean.setTotal_amount(total_amount);
				bean.setWxappid(wxappid);
			} catch (Exception e) {
				bean = null;
				// 获取token失败
				logger.error(
						"getAccessTicket error errcode:"
								+ rootElement.elementText("err_code") + ";errmsg:"
								+ rootElement.elementText("err_code_des"),e);
			}
		}
		return bean;
	}
}
